package com.zky.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zky.constants.SystemConstants;
import com.zky.domain.ResponseResult;
import com.zky.domain.dto.MenuAddDto;
import com.zky.domain.entity.Menu;
import com.zky.domain.vo.MenuTreeVo;
import com.zky.domain.vo.MenuVo;
import com.zky.domain.vo.RoleMenuTreeSelectVo;
import com.zky.enums.AppHttpCodeEnum;
import com.zky.mapper.MenuMapper;
import com.zky.service.MenuService;
import com.zky.utils.BeanCopyUtils;
import com.zky.utils.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 菜单权限表(Menu)表服务实现类
 *
 * @author makejava
 * @since 2023-08-07 14:20:24
 */
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Override
    public List<String> selectPermsByUserId(Long id) {
        //如果是管理员，返回所有的权限
        if(id == 1L){
            LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(Menu::getMenuType,SystemConstants.MENU,SystemConstants.BUTTON);
            wrapper.eq(Menu::getStatus, SystemConstants.STATUS_NORMAL);
            List<Menu> menus = list(wrapper);
            List<String> perms = menus.stream()
                    .map(Menu::getPerms)
                    .collect(Collectors.toList());
            return perms;
        }
        //否则返回所具有的权限，getBaseMapper()和注入一个MenuMapper是一样的
        return getBaseMapper().selectPermsByUserId(id);
    }

    @Override
    public List<Menu> selectRouterMenuTreeByUserId(Long userId) {
        MenuMapper menuMapper = getBaseMapper();
        List<Menu> menus = null;
        //判断是否是管理员
        if(SecurityUtils.isAdmin()){
            //如果是 获取所有符合要求的Menu
            menus = menuMapper.selectAllRouterMenu();
        }else{
            //否则  获取当前用户所具有的Menu
            menus = menuMapper.selectRouterMenuTreeByUserId(userId);
        }

        //构建tree
        //先找出第一层的菜单  然后去找他们的子菜单设置到children属性中
        List<Menu> menuTree = builderMenuTree(menus,0L);
        return menuTree;
    }

    private List<Menu> builderMenuTree(List<Menu> menus, Long parentId) {
        List<Menu> menuTree = menus.stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .map(menu -> menu.setChildren(getChildren(menu, menus)))
                .collect(Collectors.toList());

        //感觉如果不知道一共有几层菜单可以直接用这个方法递归，但现实情况是只有两层菜单，再调用一个getChildren效率高一点
//        List<Menu> menuTree = menus.stream()
//                .filter(menu -> menu.getParentId().equals(parentId))
//                .map(menu -> menu.setChildren(builderMenuTree(menus, menu.getId())))
//                .collect(Collectors.toList());
        return menuTree;
    }

    /**
     * 获取存入参数的 子Menu集合
     * @param menu
     * @param menus
     * @return
     */
    private List<Menu> getChildren(Menu menu, List<Menu> menus) {
//        List<Menu> childrenList = menus.stream()
//                .filter(m -> m.getParentId().equals(menu.getId()))
//                .map(m->m.setChildren(getChildren(m,menus)))
//                .collect(Collectors.toList());
        List<Menu> childrenList = new ArrayList<>();
        for (Menu m : menus) {
            if (m.getParentId().equals(menu.getId())) {
//                m.setChildren(getChildren(m, menus));     //可能有三层菜单
                childrenList.add(m);
            }
        }
        return childrenList;
    }

    @Override
    public ResponseResult getMenuList(String status, String menuName) {
        //根据状态进行查询，针对菜单名进行模糊查询
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasText(menuName),Menu::getMenuName,menuName);
        wrapper.eq(StringUtils.hasText(status),Menu::getStatus,status);
        //按照父菜单id和orderNum进行排序
        wrapper.orderByAsc(Menu::getParentId,Menu::getOrderNum);
        List<Menu> menus = list(wrapper);
        //将Menu封装到MenuVo中
        List<MenuVo> menuVos = BeanCopyUtils.copyBeanList(menus, MenuVo.class);
        return (ResponseResult.okResult(menuVos));
    }

    @Override
    public ResponseResult addMenu(MenuAddDto menuDto) {
        //判断该菜单是否已经存在
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getMenuName,menuDto.getMenuName());
        Menu menu = getOne(wrapper);
        if(menu != null){
            return ResponseResult.errorResult(AppHttpCodeEnum.MENU_EXIST);
        }
        save(BeanCopyUtils.copyBean(menuDto,Menu.class));
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult getMenuById(Long id) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getId,id);
        Menu menu = getOne(wrapper);
        MenuVo menuVo = BeanCopyUtils.copyBean(menu, MenuVo.class);
        return ResponseResult.okResult(menuVo);
    }

    @Override
    public ResponseResult updateMenu(MenuAddDto menuDto) {
        if (!StringUtils.hasText(menuDto.getMenuName()) ||
                !StringUtils.hasText(menuDto.getMenuType()) ||
                !StringUtils.hasText(String.valueOf(menuDto.getStatus())) ||
                !StringUtils.hasText(menuDto.getPath()) ||
                !StringUtils.hasText(String.valueOf(menuDto.getOrderNum())) ||
                !StringUtils.hasText(menuDto.getIcon())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.CONTENT_IS_BLANK);
        }
        //不能把父菜单设置为当前菜单
        if (menuDto.getParentId().equals(menuDto.getId())){
            return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR,"修改菜单'写博文'失败，上级菜单不能选择自己");
        }
        Menu menu = BeanCopyUtils.copyBean(menuDto, Menu.class);
        updateById(menu);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult deleteMenu(Long id) {
        //查询当前菜单是否有子菜单，如果有就不允许删除
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getParentId,id);
        List<Menu> menus = list(wrapper);
        if(menus.size() > 0){
            return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR,"存在子菜单不允许删除");
        }
        removeById(id);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult getMenuTree() {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        //排序 parent_id和order_num
        queryWrapper.orderByAsc(Menu::getParentId,Menu::getOrderNum);
        List<Menu> menus = list(queryWrapper);

        List<MenuTreeVo> menuTree = new ArrayList<>();
        for (Menu menu : menus) {
            if (menu.getParentId().equals(0L)) {
                MenuTreeVo tree = new MenuTreeVo();
                tree.setId(menu.getId());
                tree.setLabel(menu.getMenuName());
                tree.setParentId(menu.getParentId());
                tree.setChildren(getMenuTreeChildren(menu, menus));
                menuTree.add(tree);
            }
        }
        return ResponseResult.okResult(menuTree);
    }

    @Override
    public ResponseResult roleMenuTreeselect(Long id) {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        //排序 parent_id和order_num
        queryWrapper.orderByAsc(Menu::getParentId,Menu::getOrderNum);
        List<Menu> menus = list(queryWrapper);

        List<MenuTreeVo> menuTree = new ArrayList<>();
        for (Menu menu : menus) {
            if (menu.getParentId().equals(0L)) {
                MenuTreeVo tree = new MenuTreeVo();
                tree.setId(menu.getId());
                tree.setLabel(menu.getMenuName());
                tree.setParentId(menu.getParentId());
                tree.setChildren(getMenuTreeChildren(menu, menus));
                menuTree.add(tree);
            }
        }
        List<Long> checkedKeys = getBaseMapper().selectMenuListByRoleId(id);
        RoleMenuTreeSelectVo roleMenuTreeSelectVo = new RoleMenuTreeSelectVo(checkedKeys,menuTree);
        return ResponseResult.okResult(roleMenuTreeSelectVo);
    }

    private List<MenuTreeVo> getMenuTreeChildren(Menu menu, List<Menu> menus) {
        List<MenuTreeVo> childrenList = new ArrayList<>();
        for (Menu m : menus) {
            if (m.getParentId().equals(menu.getId())) {
                MenuTreeVo child = new MenuTreeVo();
                child.setId(m.getId());
                child.setLabel(m.getMenuName());
                child.setParentId(menu.getId());
                child.setChildren(getMenuTreeChildren(m, menus));     //有三层菜单
                childrenList.add(child);
            }
        }
        return childrenList;
    }
}

